import 'dart:collection';
import 'dart:io';

import 'package:eq/native/async/eq_timer.dart';
import 'package:eq/native/constants.dart';
import 'package:eq/native/math/eq_complex.dart';
import 'package:eq/native/math/eq_matrix.dart';
import 'package:eq/native/time/eq_time.dart';
import 'package:eq/native/core/eq_core.dart';
import 'package:eq/native/io/eq_file.dart';
import 'package:eq/native/io/eq_host.dart';
import 'package:eq/native/io/eq_stdio.dart';
import 'package:eq/native/math/eq_math.dart';
import 'package:eq/native/utils/eq_regexp.dart';
import 'package:eq/src/core.dart';
import 'package:eq/src/interface.dart';
import 'package:eq/src/interpreter.dart';
import 'package:eq/src/statement.dart';

///函数搜索工具
///
FunctionDefinition? searchFunction(String package, String identifier) {
  FunctionDefinition? functionDefinition;

  for (var entry in Interpreter.getInstance().module[package]!.functionList) {
    if (entry.name == identifier) {
      functionDefinition = entry;
      return functionDefinition;
    }
  }

  ///如果当前模块没有再搜索core模块
  for (var entry in Interpreter.getInstance().module[eq_core]!.functionList) {
    if (entry.name == identifier) {
      functionDefinition = entry;
      return functionDefinition;
    }
  }
  return functionDefinition;
}

void addEQModule(String name) {
  Module module = Module(
    name,
  );
  Interpreter.getInstance().module.putIfAbsent(name, () => module);
  switch (name) {
    case eq_core:
      addCoreFunctions(module);
      break;
    case eq_math:
      addMathFunctions(module);
      break;
    case eq_hots:
      addHostFunctions(module);
      break;
    case eq_timer:
      addTimerFunctions(module);
      break;
    case eq_time:
      addTimeFunctions(module);
      break;
    case eq_stdio:
      addStdioFunctions(module);
      break;
    case eq_file:
      addFileFunctions(module);
      break;
    case eq_regexp:
      addRegExpFunctions(module);
      break;
    case eq_complex:
      addComplexFunctions(module);
      break;
    case eq_matrix:
      addMatrixFunctions(module);
      break;
    default:
      exitApp('eq module $name not find.', 1);
  }
}

Variable? searchLocalVariable(
    LinkedList<Variable> localEnvironment, String identifier) {
  for (var v in localEnvironment) {
    if (v.name == identifier) {
      {
        return v;
      }
    }
  }
  return null;
}

Variable? searchGlobalVariable(String module, String identifier) {
  if (Interpreter.getInstance().module.containsKey(module)) {
    for (var v in Interpreter.getInstance().module[module]!.variable) {
      if (v.name == identifier) {
        return v;
      }
    }
  }

  return null;
}

void searchAndAddVariable(LinkedList<Variable>? localEnvironment, String module,
    Expression left, Value returnvalue,
    {bool isFixed = false}) {
  ///是否有本地环境，有的话是不能添加全局变量的,另外数组表达式在此只能修改
  if (localEnvironment == null) {
    for (var entry in Interpreter.getInstance().module[module]!.variable) {
      if (entry.name == left.identifier) {
        if (!entry.isFixed) {
          ///是否允许修改
          entry.value = returnvalue;
        } else {
          print("警告:${entry.name}不可修改");
        }
        return;
      }
    }

    Interpreter.getInstance()
        .module[module]!
        .variable
        .add(Variable(left.identifier, returnvalue, isFixed: isFixed));
  } else {
    for (var entry in localEnvironment) {
      if (entry.name == left.identifier) {
        if (!entry.isFixed) {
          ///是否允许修改
          entry.value = returnvalue;
        } else {
          print("局部变量,警告:${entry.name}不可修改");
        }
        return;
      }
    }

    localEnvironment
        .add(Variable(left.identifier, returnvalue, isFixed: isFixed));
  }
}

void loadModule(String name) {
  String t1;
  File f;
  if (name.toLowerCase().startsWith(pub_start)) {
    addEQModule(name);
  } else if (name.toLowerCase().startsWith(eq_start)) {
    addEQModule(name);
  } else {
    t1 = Interpreter.getInstance().proDir +
        ('\\${name.replaceAll('.', '\\')}$file_end');
    f = File(t1);
    interpreterCompile(f, name);
  }

  //固有函数load调用,传递的是全局变量,可以用来增加全局变量
  //其余模块通过此函数注册全局变量并给其他模块访问
  if (!Interpreter.getInstance().module[name]!.getLoad) {
    Interpreter.getInstance().module[name]!.setLoad = true;
    FunctionDefinition? functionDefinition = searchFunction(name, "load");
    if ((functionDefinition != null) &&
        (functionDefinition.parameter.isEmpty)) {
      StatementResult result = interpreterRun(
        name,
        functionDefinition.block.statementList,
        localEnvironment: Interpreter.getInstance().module[name]!.variable,
      );
      if (result.type == StatementResultType.ERROR_RUNTIME_RESULT) {
        Interpreter.getInstance().module[name]!.setLoad = false;
        exitApp(result.error!, 1);
      }
    }
  }
}

StatementResult arrayCacl(Value left, ArrayValue t1, ExpressionType type) {
  ArrayValue t2 = ArrayValue();
  StatementResult result = StatementResult();
  for (var e in t1.array) {
    List<Value> t3 = List.empty(growable: true);
    for (var entry in e) {
      if (type == ExpressionType.BIT_NOT_EXPRESSION) {
        if (entry.type == ValueType.INT_VALUE) {
          result.returnvalue = Value(ValueType.INT_VALUE, ~entry.value);
        } else if (entry.type == ValueType.ARRAY_VALUE) {
          result = arrayCacl(Value(ValueType.NULL_VALUE, null), entry.value,
              ExpressionType.BIT_NOT_EXPRESSION);
        } else {
          result.type = StatementResultType.ERROR_RUNTIME_RESULT;
          result.error = "表达式错误";
        }
      } else if (type == ExpressionType.LOGICAL_NOT_EXPRESSION) {
        if (entry.type == ValueType.BOOLEAN_VALUE) {
          result.returnvalue = Value(ValueType.BOOLEAN_VALUE, !entry.value);
        } else if (entry.type == ValueType.ARRAY_VALUE) {
          result = arrayCacl(Value(ValueType.NULL_VALUE, null), entry.value,
              ExpressionType.LOGICAL_NOT_EXPRESSION);
        } else {
          result.type = StatementResultType.ERROR_RUNTIME_RESULT;
          result.error = "表达式错误";
        }
      } else {
        result = binaryExpression(left, entry, type);
      }
      if (result.type == StatementResultType.ERROR_RUNTIME_RESULT) {
        return result;
      }
      t3.add(result.returnvalue);
    }
    t2.array.add(t3);
  }
  result.returnvalue = Value(ValueType.ARRAY_VALUE, t2);
  return result;
}

StatementResult arrayCaclR(ArrayValue t1, Value right, ExpressionType type) {
  ArrayValue t2 = ArrayValue();
  StatementResult result = StatementResult();
  for (var e in t1.array) {
    List<Value> t3 = List.empty(growable: true);
    for (var entry in e) {
      result = binaryExpression(entry, right, type);
      if (result.type == StatementResultType.ERROR_RUNTIME_RESULT) {
        return result;
      }
      t3.add(result.returnvalue);
    }
    t2.array.add(t3);
  }
  result.returnvalue = Value(ValueType.ARRAY_VALUE, t2);
  return result;
}

///变量类型名
String getValueTypeName(Value v) {
  switch (v.type) {
    case ValueType.BOOLEAN_VALUE:
      return 'bool';
    case ValueType.INT_VALUE:
    case ValueType.DOUBLE_VALUE:
      return 'num';
    case ValueType.STRING_VALUE:
      return 'string';
    case ValueType.REGEXP_VALUE:
      return 'regexp';
    case ValueType.COMPLEX_VALUE:
      return 'complex';
    case ValueType.ARRAY_VALUE:
      return 'matrix';
    case ValueType.NULL_VALUE:
      return 'null';
    case ValueType.FUNCTION_VALUE:
      return 'function';
    case ValueType.NATIVE_POINTER_VALUE:
      return 'native';
    case ValueType.UNDEFINED_VALUE:
      return 'undefined';
  }
}

void addNativeFunction(String name, NativeFunctionProc proc, Module module) {
  FunctionDefinition fd = FunctionDefinition(
    name,
    true,
  );
  fd.proc = proc;

  module.functionList.add(fd);
}
